﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using App1AppHandler;
using System.Timers;
using System.Drawing;
using Reborn_WorldServer;

namespace Reborn_Server.App1AppHandler
{
    public class AreaSpell : Spell
    {
        public long CastingCreatureGUID = -1;
        public int CastingCharacterID = -1;

        //List of map items effected by this area spell
        protected volatile List<MapItem> MapItems = new List<MapItem>();

        //Map info for list of map items
        protected int MapID = -1;
        protected int Instance = -1;

        //This spells starting position
        protected int CastMapX = 0;
        protected int CastMapY = 0;
        protected int CastingCreatureInt = 0;
        protected int CastingCreatureWis = 0;
        protected int CastingCreatureLevel = 0;
        protected MapItem CastMapItem = null;

        protected int TimerCounter = 0;

        protected int DurationLow = 0;
        protected int DurationHigh = 0;

        protected Timer spellTimer = new Timer(1200);

        public AreaSpell() 
        {
            spellTimer.AutoReset = false;
            spellTimer.Elapsed += new ElapsedEventHandler(SpellTimer_Expired);
        }

        virtual public bool isDangerous(Creature creature)
        {
            if (spellIcon.Offensive == true && spellIcon.SpellType == "Ground Area")
            {
                if ((spellIcon.Skill == "Fire" && creature.IgnoresFire == false) ||
                    (spellIcon.Skill == "Ice" && creature.IgnoresIce == false) ||
                    (spellIcon.Skill == "Holy" && creature.IgnoresHoly == false) ||
                    (spellIcon.Skill == "Unholy" && creature.IgnoresUnholy == false) ||
                    (spellIcon.Skill == "Magic" && creature.IgnoresMagic == false))
                {
                    return true;
                }
            }
            return false;
        }

        //This may be triggered by a pet or an effect
        public void InitializeIndirectInstantCast(CreatureBase castingCreatureBase, int CastLevel, SpellIcon _spellIcon, int MapX, int MapY, int CastingCharID, out List<MapItem> MapItemsWithin12)
        {
            InitializeInstantCast(castingCreatureBase, CastLevel, _spellIcon, MapX, MapY, out MapItemsWithin12);

            //Just Fix the IDs
            if (CastingCharID != -1)
            {
                CastingCharacterID = CastingCharID;
                CastingCreatureGUID = -1;
            }
            else
            {
                CastingCharacterID = -1;
                CastingCreatureGUID = castingCreatureBase.CreatureID;
            }
        }

        
        public void InitializeInstantCast(CreatureBase castingCreatureBase, int CastLevel, SpellIcon _spellIcon, int MapX, int MapY, out List<MapItem> MapItemsWithin12)
        {
            MapItemsWithin12 = new List<MapItem>();

            if (castingCreatureBase is Creature) CastingCreatureGUID = castingCreatureBase.CreatureID;
            if (castingCreatureBase is Character) CastingCharacterID = castingCreatureBase.ID;

            MapID = castingCreatureBase.MapID;
            Instance = castingCreatureBase.Instance;

            spellIcon = _spellIcon;
            
            //Generate Unique Spell ID
            SpellID = castingCreatureBase.GameHandler.ItemIDGen.GetSpellID();

            CastMapX = MapX;
            CastMapY = MapY;

            CastingCreatureInt = castingCreatureBase.IntelligenceTotal;
            CastingCreatureWis = castingCreatureBase.WisdomTotal;
            CastingCreatureLevel = CastLevel;

            LockItem lockItem = Managers.GameHandler.GetLockItem(MapID, Instance);
            lock (lockItem.LockObj)
            {
                foreach (MapItem mapitem in castingCreatureBase.currentMapItem.mapItemsWithin12)
                {
                    if (Math.Abs(mapitem.MapX - CastMapX) <= 12 && Math.Abs(mapitem.MapY - CastMapY) <= 12)
                        MapItemsWithin12.Add(mapitem);
                    if (mapitem.MapX == CastMapX && mapitem.MapY == CastMapY)
                        CastMapItem = mapitem;
                }
            }
        }

        //Player Character cast only
        public bool InitializeCast(CreatureBase myCreatureBase, int CastLevel, List<string> MoveList, out List<MapItem> MapItemsWithin12)
        {
            MapItemsWithin12 = new List<MapItem>();

            if (myCreatureBase is Creature) CastingCreatureGUID = myCreatureBase.CreatureID;
            if (myCreatureBase is Character) CastingCharacterID = myCreatureBase.ID;

            MapID = myCreatureBase.MapID;
            Instance = myCreatureBase.Instance;

            CastingCreatureInt = myCreatureBase.IntelligenceTotal;
            CastingCreatureWis = myCreatureBase.WisdomTotal;
            CastingCreatureLevel = CastLevel;

            //Get Spell Icon For this spell
            if (myCreatureBase.WarmSpell == null)
            {
                if (myCreatureBase is Character)
                {
                    Character character = (Character)myCreatureBase;

                    Message message = new Message();
                    message.CreatureID = character.CreatureID;
                    message.Type = "server";
                    message.Text = "Server: Spell is not ready";
                    character.AddMessage(message);

                    character.PlaySound("Ding", character.MapX, character.MapY);

                    character.SetBusy(false);
                }

                return false;
            }
            else
            {
                //Set reference to this spells Icon
                spellIcon = myCreatureBase.WarmSpell;
            }
            //Make sure spell being casted is this spell
            if (spellIcon.ClassName != this.GetType().Name)
            {
                if (myCreatureBase is Character)
                {
                    Character character = (Character)myCreatureBase;

                    Message message = new Message();
                    message.CreatureID = character.CreatureID;
                    message.Type = "server";
                    message.Text = "Server: Spell is not ready";
                    character.AddMessage(message);

                    character.PlaySound("Ding", character.MapX, character.MapY);

                    character.SetBusy(false);
                }
                return false;
            }
            //Make sure we have enough mana
            if (myCreatureBase.Mana < spellIcon.ManaCost)
            {
                myCreatureBase.WarmSpell = null;

                if (myCreatureBase is Character)
                {
                    Character character = (Character)myCreatureBase;
                    character.Update_Character();

                    Message message = new Message();
                    message.Type = "server";
                    message.CreatureID = myCreatureBase.CreatureID;
                    message.Text = "Server: Not enough mana";

                    character.AddMessage(message);
                    character.PlaySound("Ding", character.MapX, character.MapY);

                    character.SetBusy(false);
                }
                return false;
            }

            //Calculate Moves to Map Locations
            List<Point> Positions = new List<Point>();
            Positions.Add(new Point(myCreatureBase.MapX, myCreatureBase.MapY));
            Point LastPosition = new Point();
            Point NewPosition = new Point();

            LastPosition.X = myCreatureBase.MapX;
            LastPosition.Y = myCreatureBase.MapY;
            foreach (string Move in MoveList)
            {
                if (Move == "NW")
                {
                    NewPosition.X = LastPosition.X - 1;
                    NewPosition.Y = LastPosition.Y - 1;
                }
                else if (Move == "N")
                {
                    NewPosition.X = LastPosition.X - 0;
                    NewPosition.Y = LastPosition.Y - 1;
                }
                else if (Move == "NE")
                {
                    NewPosition.X = LastPosition.X + 1;
                    NewPosition.Y = LastPosition.Y - 1;
                }
                else if (Move == "E")
                {
                    NewPosition.X = LastPosition.X + 1;
                    NewPosition.Y = LastPosition.Y - 0;
                }
                else if (Move == "SE")
                {
                    NewPosition.X = LastPosition.X + 1;
                    NewPosition.Y = LastPosition.Y + 1;
                }
                else if (Move == "S")
                {
                    NewPosition.X = LastPosition.X + 0;
                    NewPosition.Y = LastPosition.Y + 1;
                }
                else if (Move == "SW")
                {
                    NewPosition.X = LastPosition.X - 1;
                    NewPosition.Y = LastPosition.Y + 1;
                }
                else if (Move == "W")
                {
                    NewPosition.X = LastPosition.X - 1;
                    NewPosition.Y = LastPosition.Y + 0;
                }
                LastPosition = NewPosition;
                Positions.Add(NewPosition);
            }

            Map CurrentMap = myCreatureBase.GameHandler.GetMap(myCreatureBase.MapID, myCreatureBase.Instance);
            List<MapItem> MapPositions = new List<MapItem>();
            List<Character> CharactersWithin4 = new List<Character>();
            foreach (MapItem mapitem in CurrentMap.MapItems)
            {
                foreach (Point position in Positions)
                {
                    if (position.X == mapitem.MapX && position.Y == mapitem.MapY)
                    {
                        MapPositions.Add(mapitem);
                    }
                }
                if (Math.Abs(mapitem.MapX - myCreatureBase.MapX) <= 4 && Math.Abs(mapitem.MapY - myCreatureBase.MapY) <= 4)
                {
                    foreach (CreatureBase creaturebase in mapitem.CreaturesBases)
                    {
                        if (creaturebase is Character)
                            CharactersWithin4.Add((Character)creaturebase);
                    }
                }
                foreach (Point position in Positions)
                {
                    if (Math.Abs(position.X - mapitem.MapX) <= 12 && Math.Abs(position.Y - mapitem.MapY) <= 12)
                    {
                        MapItemsWithin12.Add(mapitem);
                        break;
                    }
                }
            }

            LastPosition.X = myCreatureBase.MapX;
            LastPosition.Y = myCreatureBase.MapY;

            Point NewPosition2 = new Point();

            int NumMovesAvail = Positions.Count;
            for (int x = 0; x < NumMovesAvail; x++)
            {
                foreach (MapItem mapitem in MapPositions)
                {
                    if (mapitem.MapX == Positions[x].X && mapitem.MapY == Positions[x].Y)
                    {
                        NewPosition2.X = mapitem.MapX;
                        NewPosition2.Y = mapitem.MapY;

                        if ((mapitem.Motion == 0 && mapitem.Transparent == false) || (mapitem.TerrainType == "Door" && mapitem.Transparent == false))
                        {
                            NewPosition2.X = LastPosition.X;
                            NewPosition2.Y = LastPosition.Y;
                            NumMovesAvail = -1;
                            break;
                        }
                        LastPosition.X = mapitem.MapX;
                        LastPosition.Y = mapitem.MapY;
                        break;
                    }
                }
            }

            CastMapX = NewPosition2.X;
            CastMapY = NewPosition2.Y;

            foreach (MapItem mItem in MapPositions)
            {
                if (mItem.MapX == CastMapX && mItem.MapY == CastMapY)
                {
                    CastMapItem = mItem;

                    if (mItem.allowAOE == false && spellIcon.Offensive == true)
                    {
                        if (myCreatureBase is Character)
                        {
                            Character character = (Character)myCreatureBase;
                            character.Update_Character();

                            Message message = new Message();
                            message.Type = "server";
                            message.CreatureID = myCreatureBase.CreatureID;
                            message.Text = "Server: Cannot cast AOE spells here!";

                            character.AddMessage(message);
                            character.PlaySound("Ding", character.MapX, character.MapY);

                            character.SetBusy(false);
                        }

                        return false;
                    }
                    break;
                }
            }

            //Generate Unique Spell ID
            SpellID = myCreatureBase.GameHandler.ItemIDGen.GetSpellID();

            //Reduce mana and remove warm spell
            myCreatureBase.Mana = myCreatureBase.Mana - spellIcon.ManaCost;
            //Update CreatureBaseManaLater
            myCreatureBase.WarmSpell = null;

            myCreatureBase.Update_Character();

            if (myCreatureBase is Character)
            {
                Character character = (Character)myCreatureBase;

                Decimal expToAdd = System.Convert.ToDecimal(3.00 + (3.00 * (character.CastingSpeedPercentModifier / 100.00)));
                expToAdd = expToAdd + 1.5M;

                character.skillManager.AddExp(spellIcon.Skill, expToAdd);

                //character.Timer_Round_Interval = 3000 + (3000 * (character.CastingSpeedPercentModifier / 100.00));
                character.Timer_Round_Interval = 1500; // + (1500 * (character.CastingSpeedPercentModifier / 100.00));
                character.Timer_Round_Start();
            }

            foreach (Character charInRange in CharactersWithin4)
                charInRange.UpdateCreatureBaseMana(myCreatureBase);

            return true;
        }

        //This will be overridden in subclasses to do whatever spell is supposed to do
        protected virtual void SpellTimer_Expired(object source, ElapsedEventArgs e)
        {

        }
    }
}
